if (!window["vg"]) {
    window["vg"] = {};
}

if (!vg.visualization) {
    vg.visualization = {};
}

vg.visualization.PaginatedList = (function() {
    var classObject = {
        gridHeader: "groupheader",
        elementBar: "elementbar",
        paginationBar: "paginationbar",
        disabledPaginationBtn: "title4 disabled",
        enabledPaginationBtn: "title4",
        xOnMouseOut: "title4",
        xOnMouseOver: "highlighthover",
        table: "grid navigational",
        oddRow: "oddrow",
        evenRow: "evenrow",
        selected: "highlight",
        th: "_tableHeader",
        td: "_tableColumn",
        input: "_tableInput",
        container: "_tableContainer",
        tableBtn: "_tableBtn"
    };

    var paginationObj = {
        idSuffix: "_nav{btn}",
        spanClass: "runtimeSpriteImg",
        inactiveBgPos: {
            first: "-12px 0px",
            previous: "-12px -12px",
            next: "-12px -24px",
            last: "-12px -36px"
        }
    };

    //Init tasks
    var style = ".grid.navigational ._tableHeader{text-align:center;}\
				 .grid.navigational ._tableHeader, .grid.navigational tbody ._tableColumn{padding:0px 2px;border:1px solid #b6e4f3;}\
				 .grid td ._tableInput, .grid th ._tableInput {width:100%;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;border:0px}\
				 .grid th ._tableInput{color:#0C5BAA;font-weight:bold} \
				 ._tableContainer{border : 1px solid #5CAAEA; padding : 1px; background-color : white;} \
				 ._tableContainer ._tableBtn{font-weight : normal, cursor : default, float : right}";
    var styleElmt = document.createElement("style");
    styleElmt.setAttribute("type", "text/css");
    if (styleElmt.styleSheet) { //for IE
        styleElmt.styleSheet.cssText = style;
    } else { //the world
        styleElmt.innerHTML = style;
    }
    document.getElementsByTagName("head")[0].appendChild(styleElmt);

/*************************************************** DataHelper ************************************************************/
    var DataHelper = function(inputObj) {
        this.idHeaders = [];
        for (var i = 0; i < inputObj.idHeaders.length; i++) {
            this.idHeaders.push(inputObj.idHeaders[i]["dataName"]);
        }
        this.dataCursorSize = inputObj.dataCursorSize || 25;
        this.numRows = inputObj.numRows;
        this.firstData = [];
        this.lastData = [];
        try {
            this.events = {
                "onnextneeded": inputObj["events"]["onnextneeded"],
                "onpreviousneeded": inputObj["events"]["onpreviousneeded"],
                "onlastneeded": inputObj["events"]["onlastneeded"],
                "onfirstneeded": inputObj["events"]["onfirstneeded"]
            };
        } catch (ex) {
            throw "The handlers for the events onfirstneeded, onnextneeded, onpreviousneeded, onlastneeded are mandatory";
        }
        this.allDataFetched = false;
        this.changeOver = false;
        this.endReached = false;
    };

    DataHelper.prototype = (function() {
        /**
         * Returns the first set of data
         * @return {[Array]}
         */
        var getFirstData = function() {
            return getExtremeData("first", "onfirstneeded", this.firstData, this);
        };

        var getLastData = function() {
            return getExtremeData("last", "onlastneeded", this.lastData, this);
        };

        function getExtremeData(extreme, eventName, array, helperObj) {
            helperObj.recentExtreme = extreme;
            helperObj.currentPageNumber = 0;
            if (array.length == 0) {
                var data = helperObj.events[eventName]();
                if(!data) {
                    return [];
                }
                extreme == "last" && data.reverse();
                appendData(array, data, helperObj.numRows);
            }
            resetFlags(helperObj);
            return getDataSlice(array, 0, extreme == "last");
        }

        var getNextData = function() {
            resetFlags(this);
            return getNextDataSet(this, "next");
        };

        var getPreviousData = function() {
            return getNextDataSet(this, "previous");
        };

        function resetFlags(helperObj) {
            helperObj.changeOver && (helperObj.changeOver = false);
            helperObj.endReached && (helperObj.endReached = false);
        }

        function getNextDataSet(helperObj, currentAction) {
            var currentExtreme = helperObj.recentExtreme;
            if (currentExtreme == "first") {
                var nextEvent = "onnextneeded";
                var dataSet = helperObj.firstData;
                var otherDataSet = helperObj.lastData;
            } else {
                nextEvent = "onpreviousneeded";
                dataSet = helperObj.lastData;
                otherDataSet = helperObj.firstData;
                var needReverse = true;
            }
            if ((currentExtreme == "first" && currentAction == "previous") || (currentExtreme == "last" && currentAction == "next")) {
                var nextPage = helperObj.currentPageNumber - 1;
                var returnData = getDataSlice(dataSet, nextPage, needReverse);
                (currentExtreme == "first") && (nextPage == 0) && (helperObj.endReached = true);
            } else if (helperObj.allDataFetched) {
                nextPage = helperObj.currentPageNumber + 1;
                if(nextPage > (dataSet.length - 1)) {
                    return [];
                }
                if (currentExtreme == "first" || (currentExtreme == "last" && nextPage < dataSet.length - 1)) {
                    returnData = getDataSlice(dataSet, nextPage, needReverse);
                } else {
                    returnData = helperObj.getFirstData();
                    helperObj.changeOver = true;
                    nextPage = 0;
                }
            } else {
                nextPage = helperObj.currentPageNumber + 1;
                if (!dataSet[nextPage] || dataSet[nextPage].length < helperObj.numRows) {
                    var position = getLastPosition(dataSet);
                    var newData = helperObj.events[nextEvent](position, getLastDataObject(dataSet));
                    needReverse && newData.reverse();
                    var newDataLength = newData.length;
                    if (newDataLength > 0) {
                        var duplicateFound = removeDuplicates(newData, otherDataSet, helperObj.idHeaders);
                        newData.length > 0 && appendData(dataSet, newData, helperObj.numRows);
                        if (duplicateFound || newDataLength < helperObj.dataCursorSize) {
                            helperObj.allDataFetched = true;
                            mergeData(dataSet, otherDataSet, helperObj.numRows);
                        }
                    }
                }
                returnData = getDataSlice(dataSet, nextPage, needReverse);
                if (helperObj.allDataFetched && currentExtreme == "last" && nextPage == dataSet.length - 1) {
                    returnData = helperObj.getFirstData();
                    nextPage = 0;
                }
            }
            helperObj.currentPageNumber = nextPage < 0 ? 0 : nextPage;
            return returnData;
        }

        function getDataSlice(array, position, needReverse) {
            if(position == -1) {
                var dataSlice = [];
            } else {
                dataSlice = array.slice(position, position + 1)[0];
                if (dataSlice) {
                    dataSlice = dataSlice.slice(0);
                    needReverse && dataSlice.reverse();
                }
            }
            return dataSlice || [];
        }

        /**
         * To merge from first data to last data or vice versa
         * @param  {[Array]} fromArray [firstData/lastData]
         * @param  {[Array]} toArray   [lastData/firstData]
         * @param  {[Number]} numRows   [number of rows of the table]
         * @return {[type]}           [description]
         */

        function mergeData(fromArray, toArray, numRows) {
            toArray.splice(0, toArray.length);
            var mergedArray = flatten(fromArray);
            mergedArray.reverse();
            appendData(toArray, mergedArray, numRows);
        }

        function flatten(array) {
            return [].concat.apply([], array);
        }

        function appendData(dataArray, data, numRows) {
            var lastSet = getLastDataSet(dataArray);
            var lastLength = lastSet.length;
            if (lastLength > 0 && lastLength < numRows) {
                var slice = data.splice(0, numRows - lastLength);
                lastSet.push.apply(lastSet, slice);
            }
            while (data.length > numRows) {
                dataArray.push(data.splice(0, numRows));
            }
            data.length > 0 && dataArray.push(data.splice(0));
            return dataArray;
        }

        function removeDuplicates(newData, otherDataSet, idHeaders) {
            var duplicateFound = false;
            var lastData = getLastDataObject(otherDataSet);
            if (lastData) {
                for (var i = 0; i < newData.length; i++) {
                    if (isDuplicate(newData[i], lastData, idHeaders)) {
                        newData.splice(i);
                        newData.reverse();
                        newData.unshift.apply(newData, flatten(otherDataSet));
                        newData.reverse();
                        duplicateFound = true;
                        break;
                    }
                }
            }
            return duplicateFound;
        }

        function getLastPosition(dataArray) {
            return flatten(dataArray).length;
        }

        function getLastDataObject(dataArray) {
            var lastData = dataArray.slice(-1)[0];
            if(lastData) {
                lastData = lastData.slice(-1)[0];
            }
            return lastData;
        }

        function getLastDataSet(dataArray) {
            return dataArray.slice(-1)[0] || [];
        }

        function isDuplicate(data1, data2, idHeaders) {
            var duplicateFound = true;
            for (var i = 0; i < idHeaders.length; i++) {
                if (data1[idHeaders[i]] != data2[idHeaders[i]]) {
                    duplicateFound = false;
                    break;
                }
            }
            return duplicateFound;
        }

        var clearData = function() {
            this.recentExtreme = "first";
            this.currentPageNumber = 0;
            this.firstData = [];
            this.lastData = [];
            this.allDataFetched = false;
            this.changeOver = false;
        };

        var getFullData = function () {
            if(!this.allDataFetched) {
                var lastDataArray = flatten(this.lastData);
                removeDuplicates(lastDataArray, this.firstData, this.idHeaders);
                var firstDataArray = flatten(this.firstData);
                return firstDataArray.concat(lastDataArray.reverse());
            } else {
                return flatten(this.firstData);
            }
        };

        var setFirstData = function(data) {
            this.clearData();
            appendData(this.firstData, data, this.numRows);
        }

        return {
            "getFirstData": getFirstData,
            "getFirstData": getFirstData,
            "getLastData": getLastData,
            "getNextData": getNextData,
            "getPreviousData": getPreviousData,
            "clearData": clearData,
            "getFullData" : getFullData,
            "setFirstData" : setFirstData
        };
    })();
    /********************************************* End of DataHelper ********************************************************/

    /*********************************************** List class *************************************************************/
    var List = function(inputObj) {
        this.container = (inputObj.container.constructor == String ? document.getElementById(inputObj.container) : inputObj.container);
        this.container.innerHTML = "";
        this.listName = inputObj.listName;
        this.headers = inputObj.headers;
        this.idHeaders = [];
        inputObj.idHeaders = [];
        this.checkBoxWidth = inputObj.checkBoxWidth || "21px";
        this.visibleHeaders = [];
        this.tableWidth = removePx(this.checkBoxWidth);
        for (var i = 0; i < this.headers.length; i++) {
            this.tableWidth += removePx(this.headers[i].width);
            this.headers[i].isIdentifying && this.idHeaders.push(this.headers[i]) && inputObj.idHeaders.push(this.headers[i]);
            !this.headers[i].isHidden && this.visibleHeaders.push(this.headers[i]);
        }
        this.rowHeight = inputObj.rowHeight || "23px";
        this.currentDataSet = [];
        this.dataCursorSize = inputObj.dataCursorSize || 25;
        if (inputObj.numRows > this.dataCursorSize) {
            throw "Number of rows should be less than or equal to the dataCursorSize";
        }
        this.numRows = inputObj.numRows;
        this.checkedStatus = {};
        drawList(this);
        this.currentPageNumber = 0;
        this.events = {};
        drawTable(this);
        //Data Helper needs the numRows, dataCursorSize and the idHeaders for operation
        //numRows and dataCursorSize are already there. idHeaders have been added earlier
        this.dataHelper = new DataHelper(inputObj);
        //Calling first function to set the first data to the grid
        first.call(this);
    };

    var createTag = function(type, config) {
        var tag = document.createElement(type);
        if (config) {
            config.id && (tag.id = (config.id));
            config.className && (tag.className = config.className);
            for (var i in config.style) {
                tag.style[i] = config.style[i];
            }
            for (i in config.attributes) {
                tag.setAttribute(i, config.attributes[i]);
            }
            if (type != "input" && type != "table") { //for IE.... Obviously..
                tag.innerHTML = config.innerHTML ? config.innerHTML : "";
            }
            config.parent && config.parent.appendChild(tag);
        }
        return tag;
    };

    var removePx = function(str) {
        return Number(str.replace("px", ""));
    };

    var drawList = function(listObj) {
        listObj.containerDiv = createTag("div", {
            className: classObject["container"],
            parent: listObj.container
        });
        listObj.headerDiv = createTag("div", {
            className: classObject.gridHeader,
            style: {
                border: "0",
                textAlign: "left"
            },
            parent: listObj.containerDiv
        });
        listObj.headerLabel = createTag("label", {
            innerHTML: listObj.listName,
            parent: listObj.headerDiv
        });
        listObj.elementBar = createTag("div", {
            className: classObject.elementBar,
            parent: listObj.containerDiv
        });
        listObj.paginationBar = createTag("span", {
            className: classObject.paginationBar,
            parent: listObj.elementBar
        });
        var button = createTag("button", {
            style: {
                fontWeight: "normal",
                width: "17px",
                cursor: "default"
            },
            className: classObject.enabledPaginationBtn
        });
        var p = createTag("p", {
            style: {
                width: "17px"
            },
            attributes: {
                align: "left",
                xclassName: "title4",
                xonmouseout: "this.className='" + classObject.xOnMouseOut + "'",
                xonmouseover: "this.className='" + classObject.xOnMouseOver + "'"
            },
            parent: button
        });
        var span = createTag("span", {
            className: paginationObj.spanClass,
            style: {
                marginLeft: "1px"
            },
            parent: p
        });
        listObj.firstButton = createPaginationBtn(button, listObj, "first", first);
        listObj.previousButton = createPaginationBtn(button, listObj, "previous", previous);
        listObj.nextButton = createPaginationBtn(button, listObj, "next", next);
        listObj.lastButton = createPaginationBtn(button, listObj, "last", last);
    };

    var attachHandler = function(element, handler, eventName, listObj, args) {
        element[eventName] = function(eventObject) {
            var argsArr = args || [];
            argsArr.unshift(eventObject);
            handler.apply(listObj, argsArr);
        };
    };

    var drawTable = function(listObj) {
        listObj.headerTable = createTag("table", {
            className: classObject.table,
            parent: listObj.containerDiv
        });
        var headerThead = createTag("thead", {
            parent: listObj.headerTable
        });
        var checkAllTh = createTag("th", {
            style: {
                width: listObj.checkBoxWidth
            },
            parent: headerThead,
            className: classObject.th
        });

        listObj.checkAll = createCheckBox(listObj.listName + "_checkAll", checkAllTh);
        attachHandler(listObj.checkAll, checkAllHandler, "onchange", listObj);
        listObj.tableDiv = createTag("div", {
            style: {
                overflow: "hidden"
            },
            parent: listObj.containerDiv
        });
        listObj.dataTable = createTag("table", {
            className: classObject.table,
            parent: listObj.tableDiv
        });

        //adding headers
        for (var i = 0; i < listObj.visibleHeaders.length; i++) {
            var header = createTag("th", {
                style: {
                    width: listObj.visibleHeaders[i].width,
                    height: listObj.rowHeight,
                    lineHeight: listObj.rowHeight
                },
                parent: headerThead,
                className: classObject.th
            });
            createTag("input", {
                parent: header,
                className: classObject.input,
                attributes: {
                    readonly: "true",
                    value: listObj.visibleHeaders[i].displayName
                }
            });
        }
        listObj.tbody = createTag("tbody", {
            parent: listObj.dataTable
        });
        //Adding Rows
        //adding config for checkbox header
        var checkAllHeader = {
            displayName: "_checkAll",
            width: listObj.checkBoxWidth,
            propertyName: "_checkAll"
        };
        listObj.headers.unshift(checkAllHeader);
        listObj.visibleHeaders.unshift(checkAllHeader);
        for (i = 0; i < listObj.numRows; i++) {
            insertDataRow(i, listObj);
        }

        listObj.tableDiv.style.height = calculateViewHeight(listObj) + "px";
        listObj.headerTable.style.width = listObj.tableWidth + "px";
        listObj.dataTable.style.width = listObj.tableWidth + "px";
        listObj.containerDiv.style.width = listObj.tableWidth + "px";
        listObj.buttonDiv = createTag("div", {
            style: {
                height: "23px",
                borderTop: "1px solid #B6E4F3"
            },
            parent: listObj.containerDiv
        });
        listObj.cancelBtn = createTag("button", {
            className: classObject["tableBtn"],
            style: {
                width: "70px",
                marginTop: "3px"
            },
            parent: listObj.buttonDiv,
            innerHTML: "Cancel"
        });
        attachHandler(listObj.cancelBtn, cancelBtnHandler, "onclick", listObj);
        listObj.okBtn = createTag("button", {
            className: classObject["tableBtn"],
            style: {
                width: "50px",
                margin: "3px 3px 0px 0px"
            },
            parent: listObj.buttonDiv,
            innerHTML: "OK"
        });
        attachHandler(listObj.okBtn, okBtnHandler, "onclick", listObj);
    };


    var calculateViewHeight = function(listObj) {
        var lastRowInView = listObj.dataTable.rows[listObj.numRows - 1];
        return Number(lastRowInView.offsetTop) + Number(lastRowInView.offsetHeight);
    };

    var insertDataRow = function(index, listObj) {
        var row = createTag("tr", {
            className: ((index % 2 == 0) ? classObject.oddRow : classObject.evenRow),
            parent: listObj.tbody
        });
        for (var j = 0; j < listObj.visibleHeaders.length; j++) {
            var cell = createTag("td", {
                parent: row,
                className: classObject.td,
                style: {
                    height: listObj.rowHeight,
                    lineHeight: listObj.rowHeight,
                    width: listObj.visibleHeaders[j].width
                },
                attributes: {
                    align: (j == 0 ? "center" : "left")
                }
            });
            j != 0 && createTag("input", {
                parent: cell,
                className: classObject.input,
                attributes: {
                    readonly: "true"
                }
            });
        }
        attachHandler(row, rowClickHandler, "onclick", listObj, ["onrowselect"]);
        attachHandler(row, rowClickHandler, "ondblclick", listObj, ["onrowdbclick"]);
    };

    var fillData = function(listObj) {
        var allChecked = true;
        for (var i = 0; (i < listObj.numRows && i < listObj.currentDataSet.length); i++) {
            var dataObj = listObj.currentDataSet[i];
            var dataCacheKey = getDataCacheKey(dataObj, listObj);
            var checkedStatus = listObj.checkedStatus[dataCacheKey];
            var row = listObj.dataTable.rows[i];
            var checkBox = row.cells[0].childNodes[0];
            if (!checkBox) {
                checkBox = createCheckBox(i + "", row.cells[0]);
                attachHandler(checkBox, checkBoxHandler, "onchange", listObj);
            }
            checkBox.checked = checkedStatus;
            allChecked && (allChecked = checkedStatus);
            for (var k = 1; k < listObj.visibleHeaders.length; k++) {
                var dataName = listObj.visibleHeaders[k].dataName;
                var input = row.cells[k].childNodes[0];
                input.value = dataObj[dataName];
                input.setAttribute("title", dataObj[dataName]);
            }
        }
        for (; i < listObj.numRows; i++) {
            clearDataRow(listObj.dataTable.rows[i]);
        }
        listObj.currentDataSet.length == 0 && (allChecked = false);
        listObj.checkAll.checked = allChecked;
        setSelectedRow(listObj.dataTable.rows[0], listObj);
    };

    var clearDataRow = function(row) {
        for (var i = 0; i < row.cells.length; i++) {
            if (i == 0) {
                row.cells[i].innerHTML = "";
            } else {
                row.cells[i].childNodes[0].value = "";
            }
        }
    };

    var createPaginationBtn = function(button, listObj, dir, handler) {
        var newButton = button.cloneNode(true);
        newButton.id = listObj.listName.replace(/\s/g, "") + paginationObj.idSuffix.replace("{btn}", dir);
        newButton.childNodes[0].childNodes[0].style.backgroundPosition = paginationObj.inactiveBgPos[dir];
        listObj.paginationBar.appendChild(newButton);
        attachHandler(newButton, handler, "onclick", listObj);
        return newButton;
    };

    /************************************************** Handlers ************************************************************/
    function first() {
        triggerPaginationEvent(this, "first", "getFirstData");
    };

    function last() {
        triggerPaginationEvent(this, "last", "getLastData");
    };

    function next() {
        triggerPaginationEvent(this, "next", "getNextData");
    };

    function previous() {
        triggerPaginationEvent(this, "previous", "getPreviousData");
    };

    function triggerPaginationEvent(listObj, action, dataFunction) {
        saveCurrentChecks(listObj);
        var newDataSet = listObj.dataHelper[dataFunction]();
        if(newDataSet.length != 0) {
            listObj.currentDataSet = newDataSet;
            currentDataLength = listObj.currentDataSet.length;
            fillData(listObj);
            setButtons(action, currentDataLength, listObj);
        }
    };

    var setButtons = function(action, currentDataLength, listObj) {
        var buttonStats = {
            firstButton: true,
            previousButton: true,
            nextButton: true,
            lastButton: true
        };
        if(action == "first" && currentDataLength < listObj.numRows) {
            buttonStats.firstButton = false;
            buttonStats.previousButton = false;
            buttonStats.nextButton = false;
            buttonStats.lastButton = false;
        } else if (action == "first" || (action == "previous" && (listObj.dataHelper.changeOver || listObj.dataHelper.endReached))) {
            buttonStats.firstButton = false;
            buttonStats.previousButton = false;           
        } else if(action == "last" || (action == "next" && currentDataLength < listObj.numRows)) {
            buttonStats.nextButton = false;
            buttonStats.lastButton = false;
        }
        for (var i in buttonStats) {
            setButtonView(listObj[i], buttonStats[i]);
        }
    };

    var checkAllHandler = function() {
        var rows = this.dataTable.rows;
        var currentStatus = this.checkAll.checked;
        for (var i = 0; i < this.currentDataSet.length; i++) {
            var dataCacheKey = getDataCacheKey(this.currentDataSet[i], this);
            this.checkedStatus[dataCacheKey] = true;
            var checkBox = rows[i].cells[0].childNodes[0];
            checkBox && (checkBox.checked = currentStatus);
            this.events["onrowchecked"] && this.events["onrowchecked"]({
                "checked": currentStatus,
                "data": this.currentStatus[i]
            });            
        }
    };

    var checkBoxHandler = function(eventObject) {
        var checkBox = eventObject.srcElement || eventObject.target;
        var dataId = Number(checkBox.id);
        var dataCacheKey = getDataCacheKey(this.currentDataSet[dataId], this);
        this.checkedStatus[dataCacheKey] = checkBox.checked;
        verifyCheckAll(this);
        this.events["onrowchecked"] && this.events["onrowchecked"]({
            "checked": checkBox.checked,
            "data": this.currentDataSet[dataId]
        });
    };

    function verifyCheckAll(listObj) {
        var allChecked = true;
        for(var i = 0; i < listObj.currentDataSet.length; i++) {
            if(!listObj.checkedStatus[getDataCacheKey(listObj.currentDataSet[i], listObj)]) {
                allChecked = false;
                break;
            }
        }
        listObj.checkAll.checked = allChecked;
    }

    var okBtnHandler = function(keepMenu) {
        var eventObject = [];
        var allData = this.dataHelper.getFullData();
        for (var i = 0; i < allData.length; i++) {
            var dataCacheKey = getDataCacheKey(allData[i], this);
            this.checkedStatus[dataCacheKey] && eventObject.push(allData[i]);
        }
        !keepMenu && this.hideGrid();
        if (!keepMenu && this.events["onokclick"]) {
            this.events["onokclick"](eventObject);
        }
        return eventObject;
    };

    var cancelBtnHandler = function() {
        if (this.events["oncancelclick"]) {
            this.events["oncancelclick"]();
        }
    };

    var rowClickHandler = function(eventObject, eventName, fromInside) {
        var row = eventObject.currentTarget;
        if (!this.currentDataSet[row.rowIndex]) {
            return;
        }
        setSelectedRow(row, this);
        !fromInside && this.events[eventName] && this.events[eventName]({
            row: row,
            data: this.currentDataSet[row.rowIndex]
        });
    };

    var setButtonView = function(button, isEnabled) {
        button.className = classObject[isEnabled ? "enabledPaginationBtn" : "disabledPaginationBtn"];
    };

    var setSelectedRow = function(row, listObj) {
        listObj.currentSelectedRow && listObj.currentSelectedRow.classList.toggle(classObject["selected"]);
        listObj.currentSelectedRow = row;
        listObj.currentSelectedRow.classList.toggle(classObject["selected"]);
    };

    var getClickedDataIndex = function(rowIndex, listObj) {
        return (listObj.currentStartIndex + rowIndex);
    };

    /*
     * IE outdoes itself - doesn't allow to add type property to input elements dynamically for so called
     * security reasons
     */
    var createCheckBox = function(id, parent) {
        var dummy = document.createElement("div");
        dummy.innerHTML = "<input type='checkbox' id='" + id + "'>";
        var checkBox = dummy.childNodes[0];
        parent.appendChild(checkBox);
        return checkBox;
    };

    var getDataCacheKey = function(dataObj, listObj) {
        var dataCacheKey = "";
        for (var i = 0; i < listObj.idHeaders.length; i++) {
            dataCacheKey += dataObj[listObj.idHeaders[i]["dataName"]] + ";";
        }
        return dataCacheKey;
    };

    var saveCurrentChecks = function(listObj) {
        var rows = listObj.dataTable.rows;
        for(var i = 0; i < rows.length; i++) {
            var checkBox = rows[i].cells[0].childNodes[0];
            if (!checkBox) {
                break;
            }
            var dataObj = listObj.currentDataSet[i];
            var dataCacheKey = getDataCacheKey(dataObj, listObj);
            listObj.checkedStatus[dataCacheKey] = checkBox.checked;            
        }
    };

    List.prototype = (function() {
        var setFirstData = function (data) {
            if(data.length > this.dataCursorSize) {
                throw "Data length should be lesser than the set cursor size";
            }
            this.clearData();
            this.dataHelper.setFirstData(data);
            first.call(this);
        }

        var setEventListener = function(eventName, handler) {
            this.events[eventName] = handler;
        };

        var hideGrid = function() {
            this.containerDiv.style.display = "none";
        };

        var showGrid = function() {
            this.containerDiv.style.display = "block";
        };

        var setButtonVisibility = function(isVisible) {
            var display = isVisible ? "block" : "none";
            this.okBtn.style.display = display;
            this.cancelBtn.style.display = display;
        };

        var getSelection = function() {
            return okBtnHandler.call(this, true);
        };

        var getData = function() {
            return this.dataHelper.getFullData();
        };

        var clearData = function() {
            this.dataHelper.clearData();
            this.checkedStatus = {};
            this.currentDataSet = [];
            fillData(this);
            setButtons("first", 0, this);
        }

        return {
            "setEventListener": setEventListener,
            "hideGrid": hideGrid,
            "showGrid": showGrid,
            "setButtonVisibility": setButtonVisibility,
            "getSelection": getSelection,
            "getData": getData,
            "setFirstData": setFirstData,
            "clearData": clearData
        };
    })();
    return List;
})();

scriptCallback && scriptCallback("Paginated List");